﻿using Qy.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Qy.Scenario;
[AppService]
public class UserService : QyRepository<User>
{
    private readonly string cacheKey, cacheKeyLogin;
    private readonly UserDeptService _userDeptService;
    private readonly ApplicationContext _applicationContext;
    public UserService(UserDeptService userDeptService, ApplicationContext applicationContext) : base(applicationContext)
    {
        _applicationContext = applicationContext;
        cacheKey = CacheConst.CACHE_KEY_USER;
        cacheKeyLogin = CacheConst.CACHE_KEY_USER_LOGIN;
        _userDeptService = userDeptService;
    }

    public async Task<User> CheckUorP(LoginDto dto)
    {
        string pass = MD5Utility.MD5Encrypt32(dto.PassWord).ToLower();
        return await Queryable().FirstAsync(data => data.UserName == dto.UserName && data.PassWord == pass);
    }

    public async Task<List<User>> GetAllListAsync()
    {
        return await GetAllListAsync("Id asc");
    }

    /// <summary>
    /// 获取一条用户信息并缓存
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<ViewUser> GetCacheAsync(int id)
    {
        ViewUser userData = await _applicationContext.ICacheManager.GetAsync<ViewUser>(cacheKey + id);
        if (userData == null)
        {
            userData = await Queryable()
                .LeftJoin<UserGroup>((data, group) => data.GroupId == group.Id)
                .LeftJoin<UserDept>((data, group, dept) => data.DeptId == dept.Id)
                .LeftJoin<UserPost>((data, group, dept, post) => data.PostId == post.Id)
                .Where(data => data.Id == id)
                .Select((data, group, dept, post) => new ViewUser()
                {
                    DeptName = dept.Name,
                    DeptId = dept.Id,
                    PostName = post.PostName,
                    PostCode = post.PostCode,
                    PostId = post.Id,
                    GroupName = group.GroupName,
                    Id = data.Id,
                    GroupId = data.GroupId,
                    UserName = data.UserName,
                    NickName = data.NickName,
                    Status = data.Status,
                    LoginIp = data.LoginIp,
                    LoginTime = data.LoginTime,
                    Avatar = data.Avatar,
                    Phone = data.Phone,
                    Sex = data.Sex
                })
                .FirstAsync();
            await _applicationContext.ICacheManager.SetAsync(cacheKey + id, userData, TimeSpan.FromDays(31));
        }
        return userData;
    }
    /// <summary>
    /// 更新登录信息
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="ip"></param>
    public async Task<int> UpdateLoginInfoAsync(int userId, string ip)
    {
        User userData = await GetIdAsync(userId);
        userData.LoginTime = DateTime.Now;
        userData.LoginIp = ip;
        return await Context.Updateable(userData).UpdateColumns(it => new { it.LoginIp, it.LoginTime }).ExecuteCommandAsync();
    }

    public async Task<PagedInfo<ViewUser>> GetPageListAsync(UserQuery parm, int gid)
    {
        var exp = Expressionable.Create<User>();
        exp = exp.AndIF(parm.Status != null, data => data.Status == parm.Status);
        exp = exp.AndIF(parm.DeptId != 0, data => data.DeptId == parm.DeptId);
        exp = exp.AndIF(gid != 1, data => data.GroupId != 1);

        return await Queryable()
                .LeftJoin<UserGroup>((data, group) => data.GroupId == group.Id)
                .LeftJoin<UserDept>((data, group, dept) => data.DeptId == dept.Id)
                .LeftJoin<UserPost>((data, group, dept, post) => data.PostId == post.Id)
                .Where(exp.ToExpression())
                .WhereIF(!string.IsNullOrEmpty(parm.NickName), (data, cat) => data.NickName.Contains(parm.NickName))
                .WhereIF(!string.IsNullOrEmpty(parm.UserName), (data, cat) => data.UserName.Contains(parm.UserName))
                .OrderBy((data) => data.Id, OrderByType.Desc)
                .Select((data, group, dept, post) => new ViewUser()
                {
                    DeptName = dept.Name,
                    DeptId = dept.Id,
                    PostName = post.PostName,
                    PostCode = post.PostCode,
                    PostId = post.Id,
                    GroupName = group.GroupName,
                    Id = data.Id,
                    GroupId = data.GroupId,
                    UserName = data.UserName,
                    NickName = data.NickName,
                    Status = data.Status,
                    LoginIp = data.LoginIp,
                    LoginTime = data.LoginTime,
                    Avatar = data.Avatar,
                    Phone = data.Phone,
                    Sex = data.Sex
                })
                .ToPageAsync(parm);
    }
    public async Task<List<UserIdAndName>> GetNameAsync(int userId, string name = null)
    {
        return await Queryable()
                .LeftJoin<UserDept>((data, dept) => data.DeptId == dept.Id)
                .Where(data => data.Status == true)
                .WhereIF(!string.IsNullOrEmpty(name), (data, cat) => data.NickName.Contains(name))
                .WhereIF(userId > 0, data => data.Id != userId)
                .OrderBy((data) => data.Id, OrderByType.Desc)
                .Select((data, dept) => new UserIdAndName()
                {
                    DeptName = dept.Name,
                    Id = data.Id,
                    UserName = data.UserName,
                    NickName = data.NickName,
                    Status = data.Status,
                })
                .ToListAsync();
    }


    public async Task<bool> GetByUsernameAsync(string username)
    {
        return await Queryable().AnyAsync(data => data.UserName == username);
    }


    public async Task<int> Update(EditUser editUser)
    {
        User user = await GetIdAsync(editUser.Id);
        if (user == null)
            return -1;
        if (editUser.UserName != user.UserName && await GetByUsernameAsync(editUser.UserName) == false)
            return -2;
        user.DeptId = editUser.DeptId;
        user.PostId = editUser.PostId;
        user.GroupId = editUser.GroupId;
        user.UserName = editUser.UserName;
        user.NickName = editUser.NickName;
        user.Status = editUser.Status;

        if (!string.IsNullOrEmpty(editUser.PassWord))
            user.PassWord = MD5Utility.MD5Encrypt32(editUser.PassWord).ToLower();
        if (0 < await UpdateAsync(user, true))
        {
            await _applicationContext.ICacheManager.RemoveAsync(cacheKey + editUser.Id);
            return 1;
        }
        return 0;//写入数据库失败       
    }

    public async Task<int> ChStatusUpdateAsync(EditUserStatus user)
    {
        User adminUser = await GetIdAsync(user.Id);
        adminUser.Status = user.Status;
        if (0 < await UpdateAsync(adminUser, true))
        {
            await _applicationContext.ICacheManager.RemoveAsync(cacheKey + user.Id);
            return 1;
        }
        return 0;
    }

    public async Task<int> EditUserInfoUpdateAsync(EditUser editUser, int userID)
    {
        User adminUser = await GetIdAsync(userID);
        if (Extensions.IsNotEmpty(editUser.PassWord))
        {
            string oldPassWord = MD5Utility.MD5Encrypt32(editUser.OldPassword).ToLower();
            if (adminUser.PassWord != oldPassWord)
                return 0;
            adminUser.PassWord = MD5Utility.MD5Encrypt32(editUser.PassWord).ToLower();
        }
        adminUser.NickName = editUser.NickName;
        adminUser.Sex = editUser.Sex;
        adminUser.Avatar = editUser.Avatar;
        adminUser.Phone = editUser.Phone;
        await _applicationContext.ICacheManager.RemoveAsync(cacheKey + adminUser.Id);
        await _applicationContext.ICacheManager.RemoveAsync(cacheKeyLogin + adminUser.Id);
        return await UpdateAsync(adminUser, true);
    }

    public async Task<int> DeleteDelCache(int id)
    {
        await _applicationContext.ICacheManager.RemoveAsync(cacheKey + id);
        return await DeleteAsync(id);
    }

    public async Task<bool> GetByGidAsync(int gid)
    {
        return await Queryable().AnyAsync(data => data.GroupId == gid);
    }

    #region  判断部门用户权限
    /// <summary>
    /// 查询当前部门用户ID列表
    /// </summary>
    /// <param name="deptId"></param>
    /// <returns></returns>
    private async Task<List<int>> GetUserIds(int deptId)
    {
        List<User> all = await GetAllListAsync();
        List<User> userIds = all.Where(o => o.DeptId == deptId).ToList();
        List<int> ids = userIds.Select(o => o.Id).ToList();
        return ids;
    }
    /// <summary>
    /// 查询当前部门及子部门用户ID列表
    /// </summary>
    /// <param name="deptId"></param>
    /// <returns></returns>
    private async Task<List<int>> GetUserAndSonDeptIds(int deptId)
    {
        List<User> userAll = await GetAllListAsync();
        List<int> uids = new();
        List<int> deptIds = await _userDeptService.GetDeptAndSonIdsAsync(deptId);
        foreach (int did in deptIds)
        {
            List<User> userIds = userAll.Where(o => o.DeptId == did).ToList();
            List<int> ids = userIds.Select(o => o.Id).ToList();
            uids.AddRange(ids);
        }
        return uids;

    }
    /// <summary>
    /// 通过员工职务判断资源管理权限
    /// </summary>
    /// <param name="adminUser"></param>
    /// <returns></returns>
    public async Task<List<int>> UserPostAsUids(ILoginUserInfo user)
    {
        List<int> uids;
        if (user.GroupId == 1 || user.PostCode == UserPostConst.SUPREME)
            uids = new List<int>() { -1 }; //-1为显示全部,超级管理员和部门最高领导
        else if (user.PostCode == UserPostConst.MASTER || user.PostCode == UserPostConst.DEPUTY)
            uids = await GetUserAndSonDeptIds(user.DeptId);//显示自己部门及子部门员工所属资源
        else if (user.PostCode == UserPostConst.WORKER)
            uids = await GetUserIds(user.DeptId);//显示本级部门全部员工所属资源
        else
            uids = null; //默认只显示自己的或者自定义的职务 //if (user.PostCode == UserPostConst.OTHER)      
        return uids;
    }
    #endregion
}

